#!/usr/bin/perl

package MozComics::JSON;

use MozComics::Utils;
our @ISA = qw(MozComics::Utils);

use strict;
use warnings;
use JSON;

my $json = new JSON;
my $INIT_FILENAME = 'initial.json';
my $ALL_FILENAME = 'all.json';
my $LATEST_FILENAME = 'latest.json';
my $NOW = DateTime->now;
my $UPDATED_FILENAME = $NOW->ymd.' '.$NOW->hms.'.json';

sub byStrip {
	$a->{strip} <=> $b->{strip};
}


sub new {
	my $errorHeader = 'MozComics->new';
	my $className = shift(@_) or die "$errorHeader: class name not passed";
	my $guid = shift(@_) or die "$errorHeader: guid not passed";
	my $maxNew = (shift(@_) or 1);

	# create object
	my $self = {};
	bless($self, $className);

	# use passed guid to get comic
	(open(INFILE, "<$guid/$ALL_FILENAME")
	    or open(INFILE, "<$guid/$INIT_FILENAME")) 
	    or die "$errorHeader: could not open initial file: $!";
	local $/ = undef;
	my $initialJson = <INFILE>;
	close(INFILE);
	my $comic = $json->decode($initialJson) or die "$errorHeader: malformed JSON";

	$errorHeader .= " ($comic->{name})";
	my @stripQueue = ();
	my $updated = time;

	# check to make sure the new updated time is greater than the stored one
	if($updated <= $comic->{updated}) {
		die "$errorHeader: comic was updated in the future?";
	}

	$self->{guid} = $guid;
	$self->{comic} = $comic;
	$self->{name} = $comic->{name};
	$self->{maxNew} = $maxNew;
	$self->{stripQueue} = \@stripQueue;
	$self->{updated} = $updated;
	$self->{commited} = 0;

	return $self;
}


sub getLastStrip {
	my $self = shift(@_);
	my $errorHeader = "MozComics->getLastStrip ($self->{name})";

	my @strips = @{$self->{comic}->{strips}};
	my $stripsSize = @strips;
	if($stripsSize == 0) {
		die "$errorHeader: no strips found";
	}
	return $strips[$stripsSize - 1];
}


sub getStripCount {
	my $self = shift(@_);
	my $errorHeader = "MozComics->getLastStrip ($self->{name})";
	my $conditions = (shift(@_) or {});

	my $comic = $self->{comic};
	my @strips = @{$comic->{strips}};

	# build conditions to test
	my $conditionCount = 0;
	my %intConditions = ();
	my %stringConditions = ();
	for my $col (MozComics::Utils::INT_COLUMNS) {
		if(defined $conditions->{$col}) {
			$conditionCount++;
			$intConditions{$col} = $conditions->{$col};
		}
	}
	for my $col (MozComics::Utils::STRING_COLUMNS) {
		if(defined $conditions->{$col}) {
			$conditionCount++;
			$stringConditions{$col} = $conditions->{$col};
		}
	}

	# no need to search all strips if no conditions
	if($conditionCount == 0) {
		return $#strips + 1;
	}

	# search for matches
	my $count = 0;
	for my $strip (@strips) {
		my $matchFound = 1;
		while(my ($col, $value) = each(%intConditions)) {
			if($strip->{$col} != $value) {
				$matchFound = 0;
			}
		}
		while(my ($col, $value) = each(%stringConditions)) {
			if($strip->{$col} ne $value) {
				$matchFound = 0;
			}
		}

		if($matchFound) {
			$count++;
		}
	}

	return $count;
}


sub commit {
	my $self = shift(@_);
	my $errorHeader = "MozComics->commit ($self->{name})";

	if($self->{committed}) {
		die "$errorHeader: can not commit more than once";
	}
	$self->{committed} = 1;

	my @stripQueue = sort byStrip @{$self->{stripQueue}};
	my $queueSize = @stripQueue;
	if($queueSize == 0) {
		return;
	}

	my $guid = $self->{guid};
	my $comic = $self->{comic};
	$comic->{updated} = $self->{updated};
	my @strips = @{$comic->{strips}};

	# create updated file
	$comic->{strips} = \@stripQueue;
	my $updatedJson = $json->pretty->encode($comic)
	    or die "$errorHeader: error JSON encoding updated strips";

	open(UPDATED, ">$guid/$UPDATED_FILENAME")
	    or die "$errorHeader: could not open updated file for writing: $!";
	print UPDATED $updatedJson;
	close UPDATED;

	# create latest file (copy of updated file, but with convenient filename)
	open(LATEST, ">$guid/$LATEST_FILENAME")
	    or die "$errorHeader: could not open latest file for writing: $!";
	print LATEST $updatedJson;
	close LATEST;

	# create all file
	push @strips, @stripQueue;
	$comic->{strips} = \@strips;
	my $allJson = $json->pretty->encode($comic)
	    or die "$errorHeader: error JSON encoding all strips";

	open(ALL, ">$guid/$ALL_FILENAME")
	    or die "$errorHeader: could not open all file for writing: $!";
	print ALL $allJson;
	close ALL;
}

1;

__END__

=head1 NAME

MozComics::JSON - A MozComics comic object with JSON back-end

=head1 SYNOPSIS

	use MozComics::JSON;

	$comic = MozComics::JSON->new($guid);
	$comic = MozComics::JSON->new($guid, $maxNewStrips);

	# documentation of comic methods is located in MozComics::Utils

=head1 DESCRIPTION

MozComics::JSON is a class representing a MozComics comic with a JSON back-end. The class is used to easily scrape and add new strips to a comic.

For a MySQL back-end, use MozComics::MySQL.

=head2 Set-Up

File structure template:

	{COMIC_NAME}.pl            # comic scraper
	{GUID}/
		initial.json           # user generated (required)
		latest.json            # automatically generated
		all.json               # automatically generated
		{TIMESTAMP_1}.json     # automatically generated
		{TIMESTAMP_2}.json     # automatically generated


The JSON module requires a directory whose name is the GUID of the comic. This directory must be in the same directory as the scraper. The module also requires a file named initial.json inside of this directory. The initial.json file contains the JSON representing the first strip of the comic. All other files are generated when commit is called. The latest.json files contains the strips that were added on the latest commit. The {TIMESTAMP}.json files contains the strips that were added at time TIMESTAMP. The all.json file contains all the strips that have been added. When initializing the comic object, the module first tries to read all.json. If that fails, the module then reads initial.json.

More information about what the JSON files contain can be found at L<http://mozcomics.com/support/comic_data>.

More information on how these JSON files can be used within the Firefox extension can be found at L<http://mozcomics.com/support/write_code#enable_developers_tools>.

=head2 Methods

Documentation located in MozComics::Utils.

=head1 AUTHOR

Ben Parr <bparr@bparr.com>

=head1 COPYRIGHT

Copyright (c) 2009-2010 Ben Parr. All code licensed under the The MIT License (L<http://www.opensource.org/licenses/mit-license.php>)

=head1 SEE ALSO

L<MozComics::Utils>, L<MozComics::MySQL>

=cut
